package com.qs.javame.thread.tool;

import java.util.concurrent.CountDownLatch;

/**
 * 测试：Java中的并发工具类-CountDownLatch
 * 1、如何使用？
 * CountDownLatch的构造方法中需要接受一个int类型的参数作为计数器，记为N，每次调用countDownLatch.countDown()方法时N-1，
 * 当N=0时表示计数器清零，那么会在其他线程的CountDownLatch.await()方法处返回。
 *
 * 2、源码解析后的一些结论
 *  1) 构造方法初始化时，设置计数器的初始值，实际上为源码中的state变量，state变量使用volatile修饰，共享变量内存多线程下可见；
 *  2) CountDownLatch也依赖AQS同步器，通过state变量，完成倒计时器功能；
 *  3) countDown()方法的调用，实际上操作为state-1，当state=0时，tryReleaseShared(arg)方法返回true，进入执行doReleaseShared()方法，
 *  doReleaseShared()方法就是将同步队列中阻塞的线程进行唤醒操作。
 *  （通过LockSupport.unpark(s.thread)进行唤醒操作，线程被封装为Node节点对象，下面测试代码唤醒的线程为main线程对象）；
 *  4) countDownLatch.await()方法，实际上就是将当前执行的线程封装为node节点，加入同步队列中，阻塞等待。(通过LockSupport.park(this)实现)
 *  5) 还有一个很关键的点：代码的执行次序问题。可以理解为：一个线程调用countDown()方法happens-before，另外一个线程调用的await()方法。
 *
 * 3、thread.join()也可是实现类似的功能，相比之下，缺乏灵活。
 */
public class CountDownLatchTest {

    private static CountDownLatch countDownLatch = new CountDownLatch(2);

    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println(1);
            countDownLatch.countDown();
            System.out.println(2);
            countDownLatch.countDown();
        }).start();

        try {
            //main线程在这里等待countDownLatch计数器为0时，返回
            countDownLatch.await();
            System.out.println(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
